/* libue.c */
#include <winsock2.h>

/* UELogger Support */
#include "litelog.h"
extern int logfd;

/* API statement */
#include "libue.h"

/* Each request send from one process should have unique sequence number, */
/* use this global variable for this unique sequence number. */
static unsigned int sequence = 0;

/* Send the whole UE request header from socket.
 * @param[in] s Socket file descriptor used to send out the request
 * @param[in] reqheader Pointer to the request header.
 * @return UE_ERR_SUCCESS indicate success, otherwise some error occur.
 */
int sendreqheader(const int s, const ue_request_header* reqheader)
{
	int ret = UE_ERR_SUCCESS;                          /* return code */
	int len;                                           /* send/recv data length */

	dbglogex("Enter sendreqheader(%d, %x)", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, s, reqheader);

	/* send request header */
	len = send(s, (char*)reqheader, sizeof(ue_request_header), 0);
	if (len != sizeof(ue_request_header))
	{
		if (len > 0)
		{
			dbglogex("Send request incomplete, %d bytes sent.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, len);
		}
		else
		{
			dbglogex("Send request failed. Error Code: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, WSAGetLastError());
		}

		ret = UE_ERR_SOCKET;
	} /* send request header failed */

	dbglog("Exit sendreqheader()", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);
	return ret;
}

/* Read the whole UE response header from socket.
 * @param[in] s Socket file descriptor used to receive the response
 * @param[out] resheader Pointer to the ue_response_header struture to receive the response header.
 * @return UE_ERR_SUCCESS indicate success, otherwise some error occur.
 */
int readresheader(const int s, ue_response_header* resheader)
{
	int ret = UE_ERR_SUCCESS;                          /* return code */
	int len;                                           /* send/recv data length */

	dbglogex("Enter readresheader(%d, %x)", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, s, resheader);

	/* read response header */
	len = recv(s, (char*)resheader, sizeof(ue_response_header), 0);
	if (len != sizeof(ue_response_header))
	{
		if (len > 0)
		{
			dbglogex("Invalid response, %d bytes read.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, len);
		}
		else
		{
			dbglogex("Read response failed. Error Code: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, WSAGetLastError());
		}

		ret = UE_ERR_SOCKET;
	} /* read response header failed */

	dbglog("Exit readresheader()", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	return ret;
}

int readdata(const int s, char *buf, unsigned int len)
{
	int ret = UE_ERR_SUCCESS;                          /* return code */
	int result;                                        /* send/recv data length */

	dbglogex("Enter readdata(%d, %x, %d)", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, s, buf, len);

	/* loop to read all data */
	while (len > 0)
	{
		result = recv(s, buf, len, 0);
		if (result > 0)
		{
			dbglogex("Success read %d bytes data", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, result);
			buf += result;
			len -= result;
		} /* read data success */
		else
		{
			dbglogex("Read data failed. Result: %d, Error Code: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, result, WSAGetLastError());
			ret = UE_ERR_SOCKET;
			break;
		} /* read data failed */
	} /* end loop to read all data */

	dbglog("Exit readdata()", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	return ret;
}

int senddata(const int s, const char* buf, unsigned int len)
{
	int ret = UE_ERR_SUCCESS;                          /* return code */
	int result;                                        /* send/recv data length */

	dbglogex("Enter senddata(%d, %x, %d)", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, s, buf, len);

	/* loop to send out all data */
	while (len > 0)
	{
		result = send(s, buf, len, 0);
		if (result > 0)
		{
			dbglogex("Success send %d bytes data", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, result);
			buf += result;
			len -= result;
		} /* send data success */
		else
		{
			dbglogex("Send data failed. Result: %d, Error Code: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, result, WSAGetLastError());
			ret = UE_ERR_SOCKET;
			break;
		} /* send data failed */
	} /* end loop to send out all data */

	dbglog("Exit senddata()", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	return ret;
}

int ue_connect(const char* address, const unsigned short port, int* s)
{
	int ret = UE_ERR_SUCCESS;                          /* return code */
	int ipaddr;                                        /* used to store server ip address */
	struct hostent *phostentry;                        /* used to resolve server address */
	struct sockaddr_in server_addr;                    /* connection required server address structure */

	*s = 0;
	dbglogex("Enter ue_connect(%s, %d, %x)", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, address, port, s);

	/* parameter check */
	if ((address != 0) && (port > 0) && (s != 0))
	{
		/* create socket */
		*s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if (*s > 0)
		{
			/* use inet_addr() to determine if we're dealing with a name or an address */
			ipaddr = inet_addr(address);
			if (ipaddr != INADDR_NONE)
			{
				dbglogex("Input address %s is a valid IP address.", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, address);
			} /* input address is a valid IP address */
			else
			{
				dbglogex("Input address %s is not an IP address, try to resolve it.", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, address);

				phostentry = gethostbyname(address);
				if (phostentry) 
				{
					ipaddr = *((int*)phostentry->h_addr_list[0]);
					dbglogex("Resolve the address success, IP: %x.", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, ipaddr);
				} /* resolve the input address success */
				else 
				{
					dbglogex("Unknown host: %s", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, address);

					closesocket(*s);
					*s = 0;

					ret = UE_ERR_SOCKET;
				} /* resolve the input address failed */
			} /* input address is not an IP address */

			/* check whether we've get server ip address success */
			if (*s)
			{
				/* fill in the server address structure */
				server_addr.sin_family = AF_INET;
				server_addr.sin_port = htons(port);
				server_addr.sin_addr.s_addr = ipaddr;

				/* connect to server */
				if (connect(*s, (struct sockaddr*)&server_addr, sizeof(server_addr)) == 0)
				{
					dbglogex("Connect to server: %s, port: %d success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, address, port);
				} /* connect to server success */
				else
				{
					dbglogex("Connect to server: %s, port: %d failed", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, address, port);

					closesocket(*s);
					*s = 0;

					ret = UE_ERR_SOCKET;
				} /* connect to server failed */
			} /* get server ip address success */
		} /* create socket success */
		else
		{
			dbglogex("Create socket to connect server failed. Error code: %d", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, WSAGetLastError());
			ret = UE_ERR_SOCKET;
		} /* create socket failed */
	} /* parameter check success */
	else
	{
		dbglog("Invalid input parameter.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
		ret = UE_ERR_INVALID_PARAMETER;
	} /* parameter check failed */

	dbglog("Exit ue_connect", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	return ret;
}

int ue_authenticate(int s, const char* key)
{
	int ret = UE_ERR_SUCCESS;                          /* return code */
	struct sockaddr_in local_addr;                     /* local address of the socket */
	int local_addr_len;                                /* length of local address */
	ue_request_header request_header;                  /* UE request header structure for sending request */
	ue_response_header response_header;                /* UE response header structore for receiving response */

	dbglogex("Enter ue_authentication(%d, %s)", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, s, key);

	/* get socket local address */
	local_addr_len = sizeof(local_addr);
	if (!getsockname(s, (struct sockaddr*)&local_addr, &local_addr_len))
	{
		dbglogex("Get socket local address success. Local Address: %d, Local Port: %d", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, local_addr.sin_addr.s_addr, local_addr.sin_port);

		/* fill in the request */
		request_header.addr = local_addr.sin_addr.s_addr;
		request_header.identifer = GetCurrentProcessId();
		request_header.port = local_addr.sin_port;
		if (key)
			request_header.len = strlen(key) + 1;
		else
			request_header.len = 0;
		request_header.sequence = sequence++;
		request_header.version = LIB_UE_VERSION;
		request_header.request_type = UE_REQ_TYPE_AUTH;

		/* send request header */
		if (!(ret = sendreqheader(s, &request_header)))
		{
			dbglog("Send request header success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

			/* send request body */
			if (request_header.len > 0)
			{
				if (!(ret = senddata(s, key, request_header.len)))
				{
					dbglog("Send request body success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);
				} /* send request body success */
				else
				{
					dbglogex("Send request body failed with return code: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, ret);
				} /* send request body failed */
			} /* the request has body */
			else
			{
				dbglog("Empty authentecation value specified", DEBUG_LOG_LEVEL_WARN, logfd, __FILE__, __LINE__);
			} /* the request has no body */

			/* read response */
			if (!ret)
			{
				if (!(ret = readresheader(s, &response_header)))
				{
					dbglog("Read response header success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

					/* verify if the reponse is valid */
					if (request_header.addr == response_header.addr && request_header.identifer == response_header.identifer 
						&& request_header.port == response_header.port && request_header.sequence == response_header.sequence)
					{
						if (!response_header.status)
						{
							dbglog("Server authenticate success.", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);
						} /* server handle authenticate request success */
						else
						{
							dbglogex("Server authenticate failed. Response Status: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, response_header.status);
							ret = UE_ERR_INVALID_AUTHENTICATION;
						} /* server handle authenticate request failed */
					} /* response is valid */
					else
					{
						dbglog("Invalid response. Possibly the server is not UEService.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
						ret = UE_ERR_INVALID_RESPONSE;
					} /* response is invalid */

					/* TODO: read and ignore all the follow-up response on this socket to avoid security issue */

				} /* read response success */
				else
				{
					dbglogex("Read response header failed with return code: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, ret);
				} /* read response failed */
			} /* read response */
		} /* send request header success */
		else
		{
			dbglogex("Send request header failed with return code: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, ret);
		} /* send request header failed */
	} /* get socket local address success */
	else
	{
		dbglogex("Get socket local address failed. Error Code: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, WSAGetLastError());

		/* usually failure of this function caused by invalid socket file descriptor */
		ret = UE_ERR_INVALID_PARAMETER;
	} /* get socket local address failed */

	dbglog("Exit ue_authentication()", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	return ret;
}

int ue_action(int s, ue_action_data* action_data, ue_update_data **pupdate_data)
{
	int ret = UE_ERR_SUCCESS;                          /* return code */
	struct sockaddr_in local_addr;                     /* local address of the socket */
	int local_addr_len;                                /* length of local address */
	ue_request_header request_header;                  /* UE request header structure for sending request */
	ue_response_header response_header;                /* UE response header structore for receiving response */

	dbglogex("Enter ue_action(%d, %x, %x)", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, s, action_data, pupdate_data);

	/* parameter check */
	if (action_data && pupdate_data)
	{
		/* get socket local address */
		local_addr_len = sizeof(local_addr);
		if (!getsockname(s, (struct sockaddr*)&local_addr, &local_addr_len))
		{
			dbglogex("Get socket local address success. Local Address: %d, Local Port: %d", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, local_addr.sin_addr.s_addr, local_addr.sin_port);

			/* fill in the request */
			request_header.addr = local_addr.sin_addr.s_addr;
			request_header.identifer = GetCurrentProcessId();
			request_header.port = local_addr.sin_port;
			request_header.len = sizeof(ue_action_data);
			request_header.sequence = sequence++;
			request_header.version = LIB_UE_VERSION;
			request_header.request_type = UE_REQ_TYPE_ACTION;

			/* send request and get response */
			ret = ue_request(s, &request_header, (const char*)action_data, &response_header, pupdate_data);
			if (!ret)
			{
				dbglog("Send request and get response success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

				if (response_header.len > 0)
				{
					/* TODO: validate response data */
					(*pupdate_data)->items = (ue_update_item*)((char*)(*pupdate_data) + sizeof(ue_update_data));
				} /* has response data */
				else
				{
					dbglogex("No response data, should be some error occur. Server returned error: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, response_header.status);
					if (*pupdate_data)
					{
						ue_response_free(&response_header, *pupdate_data);
						*pupdate_data = NULL;
					}
					ret = UE_ERR_SERVER_ERROR;
				} /* no response data */
			} /* success send request and get response */
			else
			{
				dbglogex("Send request and get response failed with return value: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, ret);
			} /* failed to send request and get response */
		} /* get socket local address success */
		else
		{
			dbglogex("Get socket local address failed. Error Code: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, WSAGetLastError());

			/* usually failure of this function caused by invalid socket file descriptor */
			ret = UE_ERR_INVALID_PARAMETER;
		} /* get socket local address failed */
	} /* parameter check success */
	else
	{
		dbglog("Invalid parameter, the action_data or pupdate_data is null", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);

		ret = UE_ERR_INVALID_PARAMETER;
	} /* parameter check failed */

	dbglog("Exit ue_action()", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	return ret;
}

int ue_udpate(int s, int ueid_client, ue_update_data **pupdate_data)
{
	int ret = UE_ERR_SUCCESS;                          /* return code */
	struct sockaddr_in local_addr;                     /* local address of the socket */
	int local_addr_len;                                /* length of local address */
	ue_request_header request_header;                  /* UE request header structure for sending request */
	ue_response_header response_header;                /* UE response header structore for receiving response */

	dbglogex("Enter ue_udpate(%d, %d, %x)", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, s, ueid_client, pupdate_data);

	/* parameter check */
	if (pupdate_data)
	{
		/* get socket local address */
		local_addr_len = sizeof(local_addr);
		if (!getsockname(s, (struct sockaddr*)&local_addr, &local_addr_len))
		{
			dbglogex("Get socket local address success. Local Address: %d, Local Port: %d", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, local_addr.sin_addr.s_addr, local_addr.sin_port);

			/* fill in the request */
			request_header.addr = local_addr.sin_addr.s_addr;
			request_header.identifer = GetCurrentProcessId();
			request_header.port = local_addr.sin_port;
			request_header.len = sizeof(ueid_client);
			request_header.sequence = sequence++;
			request_header.version = LIB_UE_VERSION;
			request_header.request_type = UE_REQ_TYPE_UPDATE;

			/* send request and get response */
			ret = ue_request(s, &request_header, (const char*)&ueid_client, &response_header, pupdate_data);
			if (!ret)
			{
				dbglog("Send request and get response success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

				if (response_header.len > 0)
				{
					/* TODO: validate response data */
					(*pupdate_data)->items = (ue_update_item*)((char*)(*pupdate_data) + sizeof(ue_update_data));
				} /* has response data */
				else
				{
					dbglogex("No response data, should be some error occur. Server returned error: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, response_header.status);
					if (*pupdate_data)
					{
						ue_response_free(&response_header, *pupdate_data);
						*pupdate_data = NULL;
					}
					ret = UE_ERR_SERVER_ERROR;
				} /* no response data */
			} /* success send request and get response */
			else
			{
				dbglogex("Send request and get response failed with return value: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, ret);
			} /* failed to send request and get response */
		} /* get socket local address success */
		else
		{
			dbglogex("Get socket local address failed. Error Code: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, WSAGetLastError());

			/* usually failure of this function caused by invalid socket file descriptor */
			ret = UE_ERR_INVALID_PARAMETER;
		} /* get socket local address failed */
	} /* parameter check success */
	else
	{
		dbglog("Invalid parameter, the pupdate_data is null", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);

		ret = UE_ERR_INVALID_PARAMETER;
	} /* parameter check failed */

	dbglog("Exit ue_udpate()", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	return ret;
}

int ue_request(int s, ue_request_header *request_header, const char* request_data, ue_response_header *response_header, void** presponse_data)
{
	int ret = UE_ERR_SUCCESS;                          /* return code */
	fd_set readset;                                    /* used to check if socket has more data to read */
	struct timeval timeout;                            /* timeout to check if socket has more data to read */
	char ch;                                           /* used to empty socket read buffer */

	dbglogex("Enter ue_request(%d, %x, %x, %x, %x)", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, s, request_header, request_data, response_header, presponse_data);

	/* parameter check */
	if (request_header && response_header)
	{
		if (request_header->len > 0 && !request_data)
		{
			dbglogex("Invalid input parameter, request_data is null.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
			ret = UE_ERR_INVALID_PARAMETER;
		}

		/* send request */
		if (!ret)
		{
			dbglog("Begin send request...", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

			if (!(ret = sendreqheader(s, request_header)))
			{
				dbglog("Send request header success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

				/* send request body */
				if (request_header->len > 0)
				{
					if (!(ret = senddata(s, (const char*)request_data, request_header->len)))
					{
						dbglog("Send request body success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

						/* read response */
						if (!(ret = readresheader(s, response_header)))
						{
							dbglog("Read response header success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

							/* verify if the reponse is valid */
							if (request_header->addr == response_header->addr && request_header->identifer == response_header->identifer 
								&& request_header->port == response_header->port && request_header->sequence == response_header->sequence)
							{
								if (!response_header->status)
								{
									dbglog("Server response success.", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

									/* check if have response data */
									if (response_header->len > 0)
									{
										dbglog("Have response data to read.", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);
										/* read response data */
										if (presponse_data)
										{
											*presponse_data = malloc(response_header->len);
											if (*presponse_data)
											{
												dbglog("Malloc memory for response data success.", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);
												if (!(ret = readdata(s, (char*)*presponse_data, response_header->len)))
												{
													dbglog("Read response data success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);
												}
												else
												{
													dbglogex("Read response data failed with return code: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, ret);
													free(*presponse_data);
													*presponse_data = NULL;
												}
											} /* malloc memory for response data success */
											else
											{
												dbglog("Malloc memory for response data failed.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
												ret = UE_ERR_OUT_OF_MEMORY;
											} /* malloc memory for response data failed */
										} /* parameter check success */
										else
										{
											dbglogex("Invalid input parameter, presponse_data is null.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
											ret = UE_ERR_INVALID_PARAMETER;
										} /* parameter check failed */
									} /* have response data */
									else
									{
										dbglog("No response data to read.", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);
									} /* no response data */
								} /* server handle authenticate request success */
								else
								{
									dbglogex("Server handle request failed. Response Status: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, response_header->status);
									ret = UE_ERR_SERVER_ERROR;
								} /* server handle authenticate request failed */
							} /* response is valid */
							else
							{
								dbglog("Invalid response. Possibly the server is not UEService.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
								ret = UE_ERR_INVALID_RESPONSE;
							} /* response is invalid */

							/* read and ignore all the follow-up response on this socket to avoid security issue */
							FD_ZERO(&readset);
							FD_SET(s, &readset);
							timeout.tv_sec = 0;
							timeout.tv_usec = 0;
							while (select(0, &readset, NULL, NULL, &timeout) > 0)
								recv(s, &ch, 1, 0);

						} /* read response success */
						else
						{
							dbglogex("Read response header failed with return code: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, ret);
						} /* read response failed */
					} /* send request body success */
					else
					{
						dbglogex("Send request body failed with return code: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, ret);
					} /* send request body failed */
				} /* send request body */
			} /* send request header success */
			else
			{
				dbglogex("Send request header failed with return code: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, ret);
			} /* send request header failed */
		} /* send request */
	} /* parameter check success */
	else
	{
		dbglogex("Invalid input parameter, request_header or response_header is null.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);

		ret = UE_ERR_INVALID_PARAMETER;
	} /* parameter check failed */


	dbglog("Exit ue_request()", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	return ret;
}

int ue_response_free(ue_response_header *response_header, void* response_data)
{
	int ret = UE_ERR_SUCCESS;                          /* return code */

	dbglogex("Enter ue_response_free(%x, %x)", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, response_header, response_data);

	// parameter check
	if (response_data)
	{
		dbglog("Free memory for response_data", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);
		free(response_data);
	} // parameter check success

	dbglog("Exit ue_response_free()", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	return ret;
}